package cn.hdu.liang.ch6;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String[] args) {
        final Pool pool = new Pool();

        Runnable r = () -> {
            String name = Thread.currentThread().getName();
            try {
                while(true) {
                    Thread.sleep(1000);
                    String item;
                    System.out.println(name + " 获得 " + (item = pool.getItem()));
                    Thread.sleep(new Random().nextInt(1000));
                    System.out.println(name + " 放回了 " + item);
                    pool.putItem(item);

                }
            } catch(InterruptedException ie) {
                System.out.println(name + " 被打断了");
            }
        };

        ExecutorService[] executors = new ExecutorService[Pool.MAX_AVAILABLE + 1];
        for(int i = 0; i < executors.length; i++) {
            executors[i] = Executors.newSingleThreadExecutor();
            executors[i].execute(r);
        }
    }
}

class Pool {

    public static final int MAX_AVAILABLE = 3;
    private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
    private final String[] items;
    private final boolean[] used = new boolean[MAX_AVAILABLE];


    Pool() {
        items = new String[MAX_AVAILABLE];
        for(int i = 0; i < items.length; i++) {
            items[i] = "I" + i;
        }
    }

    public String getItem() throws InterruptedException {
        available.acquire();
        return getNextAvailableItem();
    }

    public void putItem(String item) {
        if(markAsUnused(item)) {
            available.release();
        }
    }

    private synchronized String getNextAvailableItem() {
        for(int i = 0; i < MAX_AVAILABLE; i++) {
            if(!used[i]) {
                used[i] = true;
                return items[i];
            }
        }
        return null;
    }

    private synchronized boolean markAsUnused(String item) {
        for(int i = 0; i < MAX_AVAILABLE; i++) {
            if(item == items[i]) {
                if(used[i]) {
                    used[i] = false;
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }
}